﻿#region NeoPatterns
// 
// NeoPatterns framework is released under LGPLv3 license.
// See http://www.opensource.org/licenses/lgpl-3.0.html for more details.
// 
// Please visit http://neopatterns.wikidot.com for more information about NeoPatterns
// 
// Copyright (c) Pascal Craponne 2008
// 
#endregion

using System;

namespace NeoPatterns.Core.Registry
{
    /// <summary>
    /// Reference to an object
    /// can be a name reference or a direct reference
    /// </summary>
    public class Ref
    {
        /// <summary>
        /// Object name, to be found by an IObjectRegistry
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// ObjectRegistry to find the object referenced by name
        /// </summary>
        public IObjectRegistry ObjectRegistry { get; private set; }

        /// <summary>
        /// Direct object reference
        /// </summary>
        public object Object { get; private set; }

        private Ref()
        {
        }

        /// <summary>
        /// Creates a reference by name.
        /// This reference is incomplete and must be used with an ObjectRegistry
        /// </summary>
        /// <param name="objectName"></param>
        /// <returns></returns>
        public static Ref ByName(string objectName)
        {
            return new Ref { Name = objectName };
        }

        /// <summary>
        /// Creates a reference by name and ObjectRegistry
        /// </summary>
        /// <param name="objectName"></param>
        /// <param name="objectRegistry"></param>
        /// <returns></returns>
        public static Ref ByName(string objectName, IObjectRegistry objectRegistry)
        {
            return new Ref { Name = objectName, ObjectRegistry = objectRegistry };
        }

        /// <summary>
        /// Creates a direct object reference
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Ref ByObject(object obj)
        {
            return new Ref { Object = obj };
        }

        /// <summary>
        /// This helper allows to use a direct literal string instead of a reference
        /// </summary>
        /// <param name="objectName"></param>
        /// <returns></returns>
        public static implicit operator Ref(string objectName)
        {
            return ByName(objectName);
        }

        /// <summary>
        /// Returns an object, by name or reference
        /// </summary>
        /// <param name="objectRegistry">Used if name is specified. Must not be null in this case</param>
        /// <returns></returns>
        public object GetObject(IObjectRegistry objectRegistry)
        {
            if (Name != null)
            {
                if (objectRegistry == null)
                    throw new ArgumentException();
                //throw new ArgumentException("Must provide an IObjectRegistry to dereference an object");
                return objectRegistry.Get(Name);
            }
            return Object;
        }

        /// <summary>
        /// Returns an object, by name+objectRegistry or reference
        /// </summary>
        /// <returns></returns>
        public object GetObject()
        {
            return GetObject(ObjectRegistry);
        }
    }
}